class _Replacer(object):

    def __init__(self):
        self.imageWithChanges = []
        self.changesIndex =- 1
        self.box = None
        self.columns = None
        self.rows = None
        self.matcher = None
        
    def setImage(self, image):
        self.imageWithChanges.append(image)
        self.changesIndex += 1
        
    def setGridDimentions(self, gridDimentions):
        self.columns = gridDimentions[0]
        self.rows = gridDimentions[1]
        
    def setBox(self,box):
        self.box = box
    def setMatcher(self, matcher):
        self.matcher = matcher
        
    def undo(self):
        if (self.changesIndex > 0):
            self.changesIndex -= 1
        return self.imageWithChanges[self.changesIndex]
          
    def redo(self):
        if(self.changesIndex < len(self.imageWithChanges) - 1):
            self.changesIndex += 1
        return self.imageWithChanges[self.changesIndex]

    def getCurrentImage(self):
        return self.imageWithChanges[self.changesIndex]

    def replaceBox(self):
                  
        unitsLocations = self.calculateUnitsLocations()
        image = self.imageWithChanges[self.changesIndex].copy()
        for location in unitsLocations:
            self.replaceUnit(image, location)
                                                       
        self.imageWithChanges.append(image)
        self.changesIndex += 1
        
        #deleting irrelevant 'redo' images, that shouldn't be reached now.
        self.removeImagesTail(self.changesIndex + 1)
                  
        return image

    def calculateUnitsLocations(self):
        upperLeftX = self.box[0]
        upperLeftY = self.box[1]
        lowerRightX = self.box[2]
        lowerRightY =  self.box[3]
        width =  lowerRightX - upperLeftX 
        hight =  lowerRightY - upperLeftY  
        unitWidth = width/self.columns
        unitHight = hight/self.rows
      
        unitMinUpperLeftX = upperLeftX
        unitMaxUpperLeftX = upperLeftX + width - unitWidth
        unitMinUpperLeftY = upperLeftY
        unitMaxUpperLeftY = upperLeftY + hight - unitHight

        #TODO - DOCUMNET THE +1
        upperLeftXlocations = range(unitMinUpperLeftX, unitMaxUpperLeftX + 1, \
                                    unitWidth)
        upperLeftYlocations = range(unitMinUpperLeftY, unitMaxUpperLeftY + 1, \
                                    unitHight)
        
        locations = [(x1, y1, x1 + unitWidth, y1 + unitHight) for x1 in \
                     upperLeftXlocations for y1 in upperLeftYlocations]

        return locations        
      

    def replaceUnit(self, mainImage, unitBox):
        unitImage = mainImage.crop(unitBox)                 
        replacedUnitImage = self.matcher.findMatch(unitImage)
        mainImage.paste(replacedUnitImage, unitBox)
        
    def removeImagesTail(self, tailStart):
        
        if tailStart<0 or tailStart>len(self.imageWithChanges)-1:
            raise IndexError()
        
        self.imageWithChanges = self.imageWithChanges[0:tailStart]
        
        

_replacer = _Replacer()

def Replacer():
    return _replacer

    
             
    
                        